package preprocessing;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.apache.commons.math.stat.descriptive.DescriptiveStatistics;
import org.apache.commons.math.stat.descriptive.SummaryStatistics;

import data.MatrixTime;


public class AvgAggregator {
	public static final DecimalFormat D_FORMATTER = new DecimalFormat("00");
	
	public static List<MatrixTime> day_avg(List<MatrixTime> ets) {
		List<MatrixTime> day_avg = new ArrayList<MatrixTime>();
		
		Map<String, List<MatrixTime>> map = new TreeMap<String, List<MatrixTime>>();
		
		for(MatrixTime et: ets) {
			int h = et.getStart().get(Calendar.HOUR_OF_DAY);
			int m = et.getStart().get(Calendar.MINUTE);
			String key = D_FORMATTER.format(h)+":"+D_FORMATTER.format(m);
			//System.out.println(key);
			List<MatrixTime> l = map.get(key);
			if(l == null) {
				l = new ArrayList<MatrixTime>();
				map.put(key, l);
			}
			l.add(et);
		}
		
		for(String k: map.keySet()) {
			List<MatrixTime> l = map.get(k);
			
			/*
			System.out.print("(14,3): ");
			for(ErlangTime x: l) 
				System.out.print(x.mat[14][3]+"; ");
			System.out.println();
			
			System.out.print("(17,4): ");
			for(ErlangTime x: l) 
				System.out.print(x.mat[17][4]+"; ");
			System.out.println();
			*/
			day_avg.add(avg(l));
		}
		
		return day_avg;	
	}
	
	//4 time-period: morning: 6:00-12:00, afternoon: 12:00-18:00, evening: 18:00-0:00, night: 0:00-06:00
	public static List<MatrixTime> day_period_avg(List<MatrixTime> ets) {
		List<MatrixTime> day_avg = new ArrayList<MatrixTime>();
		
		Map<String, List<MatrixTime>> map = new TreeMap<String, List<MatrixTime>>();
		
		for(MatrixTime et: ets) {
			int h = et.getStart().get(Calendar.HOUR_OF_DAY);
			String key = "";
			if(h >= 6 && h<12)
				key = "6";
			if(h >=12 && h<18)
				key = "12";
			if(h >=18)
				key = "18";
			if(h <6)
				key = "0";
			
			System.out.println(h+" --> "+key);
			List<MatrixTime> l = map.get(key);
			if(l == null) {
				l = new ArrayList<MatrixTime>();
				map.put(key, l);
			}
			l.add(et);
		}
		
		for(String k: map.keySet()) {
			List<MatrixTime> l = map.get(k);
			day_avg.add(avg(l));
		}
		
		return day_avg;	
	}
	
	
	//4 time-period: morning: 6:00-12:00, afternoon: 12:00-18:00, evening: 18:00-0:00, night: 0:00-06:00
	public static List<MatrixTime> day_period_std(List<MatrixTime> ets) {
		List<MatrixTime> day_std = new ArrayList<MatrixTime>();
		
		Map<String, List<MatrixTime>> map = new TreeMap<String, List<MatrixTime>>();
		
		for(MatrixTime et: ets) {
			int h = et.getStart().get(Calendar.HOUR_OF_DAY);
			String key = "";
			if(h >= 6 && h<12)
				key = "6";
			if(h >=12 && h<18)
				key = "12";
			if(h >=18)
				key = "18";
			if(h <6)
				key = "0";
			
			System.out.println(h+" --> "+key);
			List<MatrixTime> l = map.get(key);
			if(l == null) {
				l = new ArrayList<MatrixTime>();
				map.put(key, l);
			}
			l.add(et);
		}
		
		for(String k: map.keySet()) {
			List<MatrixTime> l = map.get(k);
			day_std.add(std(l));
			
			System.out.println("KEY ORDER:"+k);
		}
		
		return day_std;	
	}
	
	public static List<MatrixTime> day_std(List<MatrixTime> ets) {
		List<MatrixTime> day_std = new ArrayList<MatrixTime>();
		
		Map<String, List<MatrixTime>> map = new TreeMap<String, List<MatrixTime>>();
		
		for(MatrixTime et: ets) {
			int h = et.getStart().get(Calendar.HOUR_OF_DAY);
			int m = et.getStart().get(Calendar.MINUTE);
			String key = D_FORMATTER.format(h)+":"+D_FORMATTER.format(m);
			//System.out.println(key);
			List<MatrixTime> l = map.get(key);
			if(l == null) {
				l = new ArrayList<MatrixTime>();
				map.put(key, l);
			}
			l.add(et);
		}
		
		for(String k: map.keySet()) {
			List<MatrixTime> l = map.get(k);
			
			day_std.add(std(l));
		}
		
		return day_std;	
	}
	
	
	public static MatrixTime avg(List<MatrixTime> l) {
		double[][] avg = new double[l.get(0).getMat().length][l.get(0).getMat()[0].length];
		double[][] size = new double[avg.length][avg[0].length];
		for(int t=0; t<l.size();t++)
			for(int i=0; i<avg.length; i++)
			for(int j=0; j<avg[0].length; j++) {
				if(l.get(t).getMat()[i][j] > 0) {
					avg[i][j] = avg[i][j] + l.get(t).getMat()[i][j];
					size[i][j] ++;
				}
			}
		
		/*
		System.out.println("SIZE = (6,31): "+size[6][31]);
		System.out.println("SIZE = (25,31): "+size[25][31]);
		*/
		for(int i=0; i<avg.length; i++)
		for(int j=0; j<avg[0].length; j++) {
			if(size[i][j] > 0)
				avg[i][j] = avg[i][j] / size[i][j];
			else
				avg[i][j] = -1;
		}
		
		return new MatrixTime(avg,l.get(0).getStart(),l.get(0).getEnd(),l.get(0).getArea());
	}
	
	public static MatrixTime std(List<MatrixTime> l) {
		
		SummaryStatistics[][] ss = new SummaryStatistics[l.get(0).getMat().length][l.get(0).getMat()[0].length];
		for(int i=0;i<ss.length;i++)
			for(int j=0;j<ss[i].length;j++)
				ss[i][j] = new SummaryStatistics();
		
		double[][] std = new double[l.get(0).getMat().length][l.get(0).getMat()[0].length];
		
		for(int t=0; t<l.size();t++)
			for(int i=0; i<std.length; i++)
			for(int j=0; j<std[0].length; j++) {
				if(l.get(t).getMat()[i][j] > 0)
					ss[i][j].addValue(l.get(t).getMat()[i][j]);
			}
		
		for(int i=0; i<std.length; i++)
		for(int j=0; j<std[0].length; j++) {
			if(ss[i][j].getMax() > 0)
				std[i][j] = ss[i][j].getStandardDeviation();
			else
				std[i][j] = -1;
		}
		
		return new MatrixTime(std,l.get(0).getStart(),l.get(0).getEnd(),l.get(0).getArea());
	}
	
	
	public static MatrixTime median(List<MatrixTime> l) {
		
		DescriptiveStatistics [][] ss = new DescriptiveStatistics[l.get(0).getMat().length][l.get(0).getMat()[0].length];
		for(int i=0;i<ss.length;i++)
			for(int j=0;j<ss[i].length;j++)
				ss[i][j] = new DescriptiveStatistics();
		
		double[][] med = new double[l.get(0).getMat().length][l.get(0).getMat()[0].length];
		
		for(int t=0; t<l.size();t++)
			for(int i=0; i<med.length; i++)
			for(int j=0; j<med[0].length; j++) {
				if(l.get(t).getMat()[i][j] > 0)
					ss[i][j].addValue(l.get(t).getMat()[i][j]);
			}
		
		for(int i=0; i<med.length; i++)
		for(int j=0; j<med[0].length; j++) {
			if(ss[i][j].getMax() > 0)
				med[i][j] = ss[i][j].getPercentile(50); //median
			else
				med[i][j] = -1;
		}
		
		return new MatrixTime(med,l.get(0).getStart(),l.get(0).getEnd(),l.get(0).getArea());
	}
	
	public static double avg(MatrixTime l) {
		double sum = 0;
		double size = 0;
		
		for(int i=0; i<l.getMat().length; i++)
			for(int j=0; j<l.getMat()[0].length; j++) {
				if(l.getMat()[i][j] > 0) {
					sum += l.getMat()[i][j];
					size++;
				}
			}
		
		return (sum/size);
	}
}
